#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QCanBus>
#include <QMessageBox>
#include <QDateTime>
#include <QCanBusDeviceInfo>
#include <QVector>
#include <QFileDialog>
#include <QFile>
#include <QDataStream>



#define PLUGINS "peakcan"
#define SENDID_DATA     (0x666)
#define SENDID_INFO     (0x667)
#define RECVID          (0x668)

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    CanDev = nullptr;
    connect(this,&MainWindow::FreshApp,this,&MainWindow::FreshHandler);

    MonitoringPortAndStart_Timer = new QTimer();
    connect(MonitoringPortAndStart_Timer,&QTimer::timeout,this,&MainWindow::MonitoringPortAndStart_Timer_Handler);
    MonitoringPortAndStart_Timer->start(10);
}

MainWindow::~MainWindow()
{
    delete MonitoringPortAndStart_Timer;
    delete ui;
}

void MainWindow::MonitoringPortAndStart_Timer_Handler(void)
{
    static int once = 1;
    if(once == 1)
    {
        MonitoringPortAndStart_Timer->stop();

        QList<QCanBusDeviceInfo> list = QCanBus::instance()->availableDevices(PLUGINS);
        for(QCanBusDeviceInfo info:list)
        {
            ui->comboBox_interfaceName->addItem(info.name());
        }
        once = 0;
    }
}

void MainWindow::CanError(QCanBusDevice::CanBusError err)
{
    if(err != QCanBusDevice::NoError)
    {
        delete CanDev;
        CanDev = nullptr;
        ui->btn_connect->setText("连接");
        ui->btn_fresh->setEnabled(true);
    }
}

QString MainWindow::QByteArrayToString(QByteArray buf)
{
    QString str;
    for(int i=0;i<buf.size();i++)
    {
        str += QString("0x%1 ").arg(static_cast<quint8>(buf.at(i)),2,16,QChar('0'));
    }
    return str;
}

void MainWindow::on_btn_connect_clicked()
{
    if(CanDev == nullptr)//连接
    {
        CanDev = QCanBus::instance()->createDevice(PLUGINS,ui->comboBox_interfaceName->currentText());
        if(CanDev == nullptr)
        {
            return;
        }
        //PCAN不支持
//        QVariant fillter;
//        QList<QCanBusDevice::Filter> fillters;
//        QCanBusDevice::Filter fillter1;
//        fillter1.frameId = 0x668; // 设置你想要接收的 CAN 帧ID
//        fillter1.frameIdMask = 0x7FF; // 掩码设置为 0x7FF，表示只关注帧ID的低11位（标准帧）
//        fillter1.format = QCanBusDevice::Filter::MatchBaseFormat; // 指定帧类型为标准帧
//        fillter1.type = QCanBusFrame::DataFrame; // 指定过滤器类型为匹配帧ID

//        fillters.append(fillter1);
//        fillter.setValue(fillters);

//        CanDev->setConfigurationParameter(QCanBusDevice::RawFilterKey,QVariant(fillter));
        CanDev->setConfigurationParameter(QCanBusDevice::BitRateKey,QVariant(500000));
        CanDev->setConfigurationParameter(QCanBusDevice::CanFdKey,QVariant(false));
        if(!CanDev->connectDevice())
        {
            delete CanDev;
            CanDev = nullptr;
            return;
        }

        connect(CanDev,&QCanBusDevice::errorOccurred,this,&MainWindow::CanError);

        ui->btn_connect->setText("断开");
        ui->btn_fresh->setEnabled(false);
    }
    else
    {
        delete CanDev;
        CanDev = nullptr;
        ui->btn_connect->setText("连接");
        ui->btn_fresh->setEnabled(true);
    }
}

void MainWindow::on_btn_fresh_clicked()
{
    QList<QCanBusDeviceInfo> list = QCanBus::instance()->availableDevices(PLUGINS);
    ui->comboBox_interfaceName->clear();
    for(QCanBusDeviceInfo info:list)
    {
        ui->comboBox_interfaceName->addItem(info.name());
    }
}

void MainWindow::on_tbtn_Select_clicked()
{
    QString FilePath = QFileDialog::getOpenFileName(NULL,"程序下载","C:/Users/Administrator/Desktop","*.bin");
    ui->lineEdit_filePath->setText(FilePath);
}

//下载文件
void MainWindow::on_btn_dowmload_clicked()
{
    ui->btn_dowmload->setEnabled(false);
    ui->btn_connect->setEnabled(false);
    emit FreshApp();
    ui->btn_dowmload->setEnabled(true);
    ui->btn_connect->setEnabled(true);
}

void MainWindow::FreshHandler(void)
{
    QString path = ui->lineEdit_filePath->text();
    quint64 FileLen;
    QFile file(path);
    int ReadLen;
    quint8 step_flag = 0;
    ui->label_schedule->setText("0%");
    if(CanDev == nullptr)
    {
        QMessageBox::warning(this,"警告","设备未连接");
        return;
    }

    if(!file.exists())
    {
        QMessageBox::warning(this,"警告","文件不存在");
        return;
    }

    if(file.open(QFile::ReadOnly))
    {
       QDataStream DStream(&file);
       FileLen = file.size();
       QByteArray buf(8,0);
       QByteArray info;
       int status;
       bool NCK_FLAG = false;
       quint32 sequence = 0;
       int test_len = 0;

       info.append(static_cast<quint8>(REPLY_HANDSHAKE));
       WriteFrame(info,SENDID_INFO);

       for(int i=0;i<20;i++)
       {
          status = WaitInfoFrame(REPLY_HANDSHAKE,1000);
          if(status == 1)
          {
            step_flag = 1;
            break;
          }
          else if(status == -1)
          {
            QMessageBox::warning(this,"警告","终止传输");
            file.close();
            return;
          }
       }
       if(step_flag != 1)
       {
           QMessageBox::warning(this,"警告","握手失败");
           file.close();
           return;
       }

       SendHandShack(static_cast<quint32>(FileLen));
       status = WaitInfoFrame(REPLY_ACK,-1);
       if(status == -1)
       {
         QMessageBox::warning(this,"警告","终止传输");
         file.close();
         return;
       }
       while(1)
       {
           WriteInfoFrame(sequence);
           if(!NCK_FLAG)
           {
             ReadLen = DStream.readRawData(buf.data(),8);
           }

           if(ReadLen != 0)
           {
               WriteFrame(buf,SENDID_DATA);
               test_len +=  ReadLen;
           }
           else
           {
               WriteInfoFrame(SEND_EOT);
               file.close();
               ui->label_schedule->setText(QString("%1%").arg(100,0,10));
               return;
           }
           step_flag = 0;
           for(int i=0;i<10;i++)
           {
               status = WaitInfoFrame(REPLY_ACK,1000);
               if(status == 1)
               {
                   step_flag = 1;
                   NCK_FLAG = false;
                   sequence++;
                   ui->label_schedule->setText(QString("%1%").arg((test_len*100/FileLen),0,10));
                   break;
               }
               else if(status == -2)
               {
                   step_flag = 1;
                   NCK_FLAG = true;
                   break;
               }
               else if(status == -1)
               {
                 WriteInfoFrame(SEND_BREAK_UP);
                 QMessageBox::warning(this,"警告","终止传输");
                 file.close();
                 return;
               }
           }
           if(step_flag!=1)
           {
               WriteInfoFrame(SEND_BREAK_UP);
               QMessageBox::warning(this,"警告","写入超时");
               file.close();
               return;
           }

       }
    }
    else
    {
        QMessageBox::warning(this,"警告","文件打开失败");
    }

}
bool MainWindow::SendHandShack(quint32 filesize)
{
    bool state = false;
    QByteArray data;
    QCanBusFrame frame;

    for(int i=3;i>=0;i--)
    {
        data.append(static_cast<quint8>( (filesize>>(i*8))&0x000000FF ));
    }
    data.append(static_cast<quint8>(0xFF));
    data.append(static_cast<quint8>(0xFF));
    data.append(static_cast<quint8>(0xFF));
    data.append(static_cast<quint8>(0xFF));
    frame.setPayload(data);
    frame.setFrameId(SENDID_INFO);
    frame.setFrameType(QCanBusFrame::DataFrame);
    frame.setExtendedFrameFormat(false);
    if(CanDev != nullptr)
    {
        state = CanDev->writeFrame(frame);
        CanDev->waitForFramesWritten(-1);
    }
    return state;
}

bool MainWindow::WriteInfoFrame(quint32 value)
{
     bool state = false;
     QByteArray data;
     QCanBusFrame frame;

     for(int i=3;i>=0;i--)
     {
         data.append(static_cast<quint8>( (value>>(i*8))&0x000000FF ));
     }
     frame.setPayload(data);
     frame.setFrameId(SENDID_INFO);
     frame.setFrameType(QCanBusFrame::DataFrame);
     frame.setExtendedFrameFormat(false);
     if(CanDev != nullptr)
     {
         state = CanDev->writeFrame(frame);
         CanDev->waitForFramesWritten(-1);
     }
     return state;
}

bool MainWindow::WriteFrame(QByteArray data,quint16 stID)
{
    bool state = false;
    QCanBusFrame frame;
    frame.setPayload(data);
    frame.setFrameId(stID);
    frame.setFrameType(QCanBusFrame::DataFrame);
    frame.setExtendedFrameFormat(false);
    if(CanDev != nullptr)
    {
        state = CanDev->writeFrame(frame);
        CanDev->waitForFramesWritten(-1);
    }
    return state;
}

void MainWindow::wait(int msec)
{
    QTime TImer = QTime::currentTime().addMSecs(msec);
    while(QTime::currentTime()<TImer)
    {
        QCoreApplication::processEvents(QEventLoop::AllEvents,1);
    }
}

int MainWindow::WaitInfoFrame(quint8 flag,int timeout)
{
    QVector<QCanBusFrame> frame_buf;
    QByteArray data;

    if(CanDev->waitForFramesReceived(timeout))
    {
      frame_buf = CanDev->readAllFrames();
      for (QCanBusFrame frame:frame_buf)
      {
          if(frame.frameId() == RECVID)
          {
              data = frame.payload();
              if( flag == (quint8)data.at(0) )
              {
                  return 1;
              }
              else if((quint8)data.at(0) == REPLY_BREAK_UP)
              {
                  return -1;
              }
              else if((quint8)data.at(0) == REPLY_NAK)
              {
                  return -2;
              }
          }
      }
    }


    return 0;
}

